home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / oct_dump.cq / oct_dump.c
Text File  |  1985-05-09  |  15KB  |  714 lines

  1. /*
  2.  * od.c 1-16-85 kpc
  3.  * this is a replica of the UNIX od (octal dump) command
  4.  * with some extensions.
  5.  *
  6.  * the spec for this command comes from the 7th edition Berkely UNIX manual
  7.  *
  8.  * NOTE: this program should also dump directories. (But! Alas, it does not.)
  9.  *
  10.  * usage:
  11.  *     od [-bcduoxDUOXw] [-B{odxc}] [-A{odx}] [file] [[+]offset[.][b]]
  12.  *
  13.  *     'file' - is the file to be dumped, if missing stdin is read.
  14.  *     'offset' - specifies the offset into the file where dumping is to begin
  15.  *           this is normally in octal bytes, unless a period '.' is
  16.  *           appended to the offset then it is interpreted as decimal bytes
  17.  *           if a 'b' is appended to the offset then it is interpreted as
  18.  *           being the number of 512 byte blocks to skip.
  19.  *           If the file argument is omitted, the offset must be preceeded
  20.  *           by a '+'.  All offsets start with zero, the first byte of a
  21.  *           file is at offset zero, the first block of a file is at offset
  22.  *           zero.
  23.  *
  24.  *     dumping continues until end-of-file.
  25.  *
  26.  *     a - ???
  27.  *     w - produce wide (132 column) output  this prints 24 bytes per line
  28.  *       versus 16 bytes per line.
  29.  *
  30.  *     b - interpret bytes in octal
  31.  *     c - interpret bytes in ASCII. certain characters appear as C escapes;
  32.  *       null = \0, bs = \b, ff = \f, nl = \n, cr = \r, tab = \t others are
  33.  *       displayed as 3-digit octal number.
  34.  *
  35.  *     d - interpret shorts in decimal (16 bits)
  36.  *     o - interpret shorts in octal   (16 bits)
  37.  *     x - interpret shorts in hex     (16 bits)
  38.  *
  39.  *     D - interpret longs in decimal  (32 bits)
  40.  *     O - interpret longs in octal    (32 bits)
  41.  *     X - interpret longs in hex      (32 bits)
  42.  *
  43.  *     A{odx} - specifies the style that the offset should displayed in.
  44.  *       o - octal bytes, x- hex bytes, d - decimal bytes.
  45.  *
  46.  *     B{odxc} - specifies the style that bytes should be displayed in.
  47.  *       o - octal bytes, x- hex bytes, d - decimal bytes.
  48.  *           this is an alternative to the -b and -c opts above
  49.  *
  50.  *[1] EDIT 1      1-21-85 kpc
  51.  *[1]      od now prints the offset 'loffset' after hitting EOF, this
  52.  *[1]      enables the user to determine the exact end of file.
  53.  */
  54.  
  55. /*  #define DEBUG */
  56.  
  57. #include <stdio.h>
  58. #include <ctype.h>
  59.  
  60. static char _sccsid[] ={ "@(#)od.c  v1.1  1-21-85  kpc"};
  61.  
  62. #define    OCT       (0x01)
  63. #define    DEC       (0x02)
  64. #define    USGN    (0x04)
  65. #define    HEX       (0x08)
  66. #define    ASC       (0x10)
  67.  
  68. #define    BLANK   (0x80)
  69.  
  70.  
  71. #define    NARROW  (16)     /* number of bytes to print */
  72. #define    WIDE    (24)     /* number of bytes to print */
  73.  
  74. #define    FALSE   (0)
  75. #define    TRUE    (1)
  76.  
  77. #define    BLOCK_SIZ   (512)
  78. #define    MAX_BUF     (48)
  79.  
  80. #define    SWITCHAR    '-'
  81.  
  82.  
  83. /* mode for fopen() */
  84. char   opn_mode[] ={ "rb"};
  85.  
  86. int    Off_prflg; /* whether or not the offset has been printed out yet */
  87.  
  88.  
  89. main( argc, argv)
  90. int    argc;
  91. char   **argv;
  92. {
  93.    int       ap,       /* int pointer into argv */
  94.        fn_p,   /* where the file name is in argv */
  95.        off_p;  /* where the offset spec is in argv */
  96.  
  97.    int       width;  /* width of output */
  98.  
  99.    int       off_opt,    /* print fmt for the offset */
  100.        byt_opt,    /* print fmt for the byt specs */
  101.        sht_opt,    /* print fmt for the short specs */
  102.        lng_opt;    /* print fmt for the long specs */
  103.  
  104.    int       num_byt;    /* number of bytes in the buffer */
  105.    char    buf[ MAX_BUF + 1];  /* guess */
  106.    char    l_buf[MAX_BUF + 1]; /* the last buf that was read in */
  107.                    /* used to implement output compaction */
  108.    int       quiet_flg;  /* this flag keeps track of the number of duplicate */
  109.                /* output lines so we can shut up during blocks of  */
  110.                /* duplicate records  */
  111.  
  112.    FILE    *fp;
  113.  
  114.  
  115.    long    loffset,    /* cur offset into file */
  116.        ioffset;    /* the initial offset */
  117.  
  118.    int       eof;
  119.    int       c;           /* input character */
  120.    int       msk;        /* msk to index the option flags */
  121.  
  122.    extern FILE *fopen();
  123.  
  124.    /* set defaults */
  125.    off_opt = OCT;
  126.    sht_opt = 0;
  127.  
  128.    byt_opt = 0;
  129.    lng_opt = 0;
  130.  
  131.    fp = stdin;
  132.    loffset = 0L;
  133.    ioffset = 0L;
  134.  
  135.    width = NARROW;
  136.  
  137.  
  138.    /* scan argv */
  139.    /* set our flag/pointers */
  140.    fn_p = -1;
  141.    off_p = -1;
  142.  
  143.    /* now we're ready; if there were no opts, the loop falls through */
  144.    /* and the defaults hold */
  145.    for( ap = 1; ap < argc; ap++)
  146.        if( argv[ap][0] == SWITCHAR )
  147.        {
  148.        /* then process as an option */
  149.        /* we need a few local variables to rip the strings apart */
  150.        char    *cp;
  151.  
  152.        /* here is a special case of only a '-' being entered */
  153.        if( argv[ap][1] == '\0')
  154.            /* this deserves the usage message */
  155.            pr_usage();
  156.  
  157.        for( cp = &argv[ap][1]; *cp; cp++)
  158.            switch( *cp)
  159.            {
  160.            /* bytes as octal */
  161.            case 'b':
  162.                byt_opt |= OCT;
  163.                break;
  164.  
  165.            /* bytes as... 'B' uses the next char as an argument */
  166.            case 'B':
  167.                switch( *(++cp))
  168.                {
  169.                case 'o':
  170.                    byt_opt |= OCT;
  171.                    break;
  172.  
  173.                case 'd':
  174.                    byt_opt |= DEC;
  175.                    break;
  176.  
  177.                case 'x':
  178.                    byt_opt |= HEX;
  179.                    break;
  180.  
  181.                case 'c':
  182.                    byt_opt |= ASC;
  183.                    break;
  184.  
  185.                default:
  186.                    fprintf(stderr,
  187.                    "od: bad option 'B' argument: (%c)\n",*cp);
  188.                    pr_usage();
  189.                }
  190.                break;
  191.  
  192.            /* bytes as asc */
  193.            case 'c':
  194.                byt_opt |= ASC;
  195.                break;
  196.  
  197.  
  198.            /* shorts as decimal */
  199.            case 'd':
  200.                sht_opt |= USGN;
  201.                break;
  202.  
  203.            /* shorts as unsigned decimal */
  204.            case 'u':
  205.                sht_opt |= USGN;
  206.                break;
  207.  
  208.            /* shorts as octal */
  209.            case 'o':
  210.                sht_opt |= OCT;
  211.                break;
  212.  
  213.            /* shorts as hex */
  214.            case 'x':
  215.                sht_opt |= HEX;
  216.                break;
  217.  
  218.  
  219.            /* longs as decimal */
  220.            case 'D':
  221.                lng_opt |= USGN;
  222.                break;
  223.  
  224.            /* longs as unsigned decimal */
  225.            case 'U':
  226.                lng_opt |= USGN;
  227.                break;
  228.  
  229.            /* longs as octal */
  230.            case 'O':
  231.                lng_opt |= OCT;
  232.                break;
  233.  
  234.            /* longs as hex */
  235.            case 'X':
  236.                lng_opt |= HEX;
  237.                break;
  238.  
  239.  
  240.            /* wide output */
  241.            case 'w':
  242.                width = WIDE;
  243.                break;
  244.  
  245.            /* offset displayed as... */
  246.            case 'A':
  247.                /* look for an argument */
  248.                switch( tolower( *(++cp) ) )
  249.                {
  250.                case 'o':
  251.                    off_opt = OCT;
  252.                    break;
  253.  
  254.                case 'd':
  255.                    off_opt = DEC;
  256.                    break;
  257.  
  258.                case 'x':
  259.                    off_opt = HEX;
  260.                    break;
  261.  
  262.                default:
  263.                    fprintf(stderr,
  264.                    "od: bad option 'A' argument: (%c)\n",*cp);
  265.                    pr_usage();
  266.                }
  267.                break;
  268.  
  269.            /* unknown option */
  270.            default:
  271.                /* this never returns */
  272.                pr_usage();
  273.            }
  274.  
  275.        }
  276.        else if( argv[ap][0] == '+' )
  277.        {
  278.        /* special offset indication */
  279.        off_p = ap;
  280.        }
  281.        else
  282.        if( fn_p == -1)
  283.        {
  284.            /* assume it is the file spec */
  285.            fn_p = ap;
  286.        }
  287.        else if( off_p == -1)
  288.        {
  289.            /* we can assume it is the starting offset spec */
  290.            off_p = ap;
  291.        }
  292.        else
  293.            pr_usage();
  294.  
  295.    /*=================================*/
  296.  
  297.    /* the default (short OCT) if nothing else is specified */
  298.    if( byt_opt == 0 && sht_opt == 0 && lng_opt == 0 )
  299.        sht_opt = OCT;
  300.  
  301.    /* now we can deal with the file name and the offset */
  302.    /* file specified? */
  303.    if( fn_p != -1)
  304.        if( (fp = fopen( argv[fn_p], opn_mode)) == NULL)
  305.        {
  306.        fprintf(stderr, "od: couldnt open input file (%s)\n", argv[fn_p]);
  307.        exit( 2);
  308.        }
  309.  
  310.    /* offset specified? */
  311.    if( off_p != -1)
  312.    {
  313.        /* now this could be a little trickier */
  314.        /* need some local variables */
  315.        char    *cp,       /* rip through the string */
  316.            *opt;       /* used to look for options */
  317.        int     mult = 1,   /* multiplier for block offsets */
  318.            base = 8;   /* radix of offset */
  319.  
  320.        cp = argv[off_p];
  321.  
  322.        /* skip possible indicator */
  323.        if( *cp == '+')
  324.        cp++;
  325.  
  326.        /* set opt to the end of string */
  327.        opt = cp;
  328.        while( *opt )
  329.        opt++;
  330.  
  331.        opt--;
  332.  
  333.        if( !isdigit( *opt & 0x7f) )
  334.        {
  335.        /* could be a 'b' or a '.' */
  336.        if( tolower( *opt ) == 'b')
  337.        {
  338.            mult = BLOCK_SIZ;
  339.            opt--;
  340.        }
  341.  
  342.        if( *opt == '.')
  343.            base = 10;
  344.        else if( !isdigit( *opt & 0x7f))
  345.        {
  346.            fprintf(stderr,"od: invalid offset spec: (%s)\n", cp);
  347.            exit( 3);
  348.        }
  349.        else
  350.            opt++;       /* dont obliterate a good digit */
  351.  
  352.        /* terminate the string */
  353.        *opt = '\0';
  354.        }
  355.  
  356.        /* convert to integer */
  357.        while( isdigit( *cp))
  358.        ioffset = ioffset * base + (*cp++ - '0');
  359.  
  360.        /* if its a block offset, then... */
  361.        ioffset *= mult;
  362.    }
  363.  
  364.  
  365.    /*
  366.     * all options have been dealt with and all flags set accordingly
  367.     * we are ready to to the dump
  368.     *  But first! we must seek to the right spot in the file
  369.     */
  370.    loffset = ioffset;
  371.  
  372.    if( ioffset != 0L )
  373.    {
  374.        int     fd;
  375.        unsigned    cnt;
  376.        char    eat_buf[ BLOCK_SIZ];
  377.  
  378.        fd = fileno( fp);
  379.  
  380. #ifdef DEBUG
  381.        printf("ioffset is: %ld. 0%lo\n", ioffset, ioffset );
  382.  
  383.        if( isatty( fd) == 1)
  384.        printf("is tty\n");
  385. #endif
  386.  
  387.        while( ioffset > 0L)
  388.        {
  389.        cnt = (ioffset >= BLOCK_SIZ) ? (BLOCK_SIZ) : (ioffset);
  390.  
  391.        if( read( fd, eat_buf, cnt ) != cnt )
  392.        {
  393.            fprintf(stderr,"od: unable to read %d bytes\n", cnt);
  394.            exit( 4);
  395.        }
  396.  
  397.        ioffset -= cnt;
  398.        }
  399.    }
  400.  
  401.  
  402.    /* ok, now we can dump the file */
  403.    eof = FALSE;
  404.  
  405. #ifdef DEBUG
  406.    printf("oopt: 0x%02x  bopt: 0x%02x sopt: 0x%02x lopt: 0x%04x\n",
  407.        off_opt, byt_opt, sht_opt, lng_opt);
  408. #endif
  409.  
  410.    /* clear out the last buffer */
  411.    bclear( l_buf, MAX_BUF + 1);
  412.    quiet_flg = -1;
  413.  
  414.    while( !eof )
  415.    {
  416.        bclear( buf, MAX_BUF + 1);
  417.  
  418.        /* get upto MAX_BUF bytes */
  419.        for( num_byt=0; num_byt < width && (c = fgetc( fp)) != EOF; num_byt++)
  420.        buf[num_byt] = c;
  421.  
  422.        /* if EOF then remember it */
  423.        if( c == EOF)
  424.        eof = TRUE;
  425.  
  426.        /*
  427.     * the following ugly nested if stmnt implements the quiet
  428.     * mode of operation.  ie only printing 2 duplicate lines,
  429.     * and then a '*' line until a record that is different is read.
  430.     */
  431.        if( bcmp( l_buf, buf, MAX_BUF + 1))
  432.        {
  433.        if( quiet_flg == 2)
  434.            /* we have already printed the '*' */
  435.            continue;
  436.        else if( quiet_flg == 1)
  437.        {
  438.            /* then we don't need to dump this buf */
  439.            /* but we do need to say something */
  440.            printf("*\n");
  441.            quiet_flg = 2;
  442.            continue;
  443.        }
  444.        else if( quiet_flg == 0)
  445.            /* this and the prev rec are equal, dump it */
  446.            quiet_flg = 1;
  447.        else
  448.            quiet_flg = 0;
  449.        }
  450.        else
  451.        {
  452.        /* they weren't equal */
  453.        quiet_flg = 0;
  454.        bcpy( l_buf, buf, MAX_BUF + 1);
  455.        }
  456.  
  457.  
  458. #ifdef DEBUG
  459.        printf("num_byt: %d\n", num_byt);
  460. #endif
  461.  
  462.        /* print the offset out */
  463.        Off_prflg = FALSE;
  464.  
  465.        for( msk = OCT; msk <= ASC; msk<<=1)
  466.        {
  467. #ifdef DEBUG
  468.        printf("msk: 0x%02x\n", msk);
  469. #endif
  470.        if( byt_opt & msk)
  471.        {
  472.            pr_off( off_opt, loffset);
  473.            pr_byte( byt_opt & msk, num_byt, buf);
  474.        }
  475.  
  476.        if( sht_opt & msk)
  477.        {
  478.            pr_off( off_opt, loffset);
  479.            pr_short( sht_opt & msk, num_byt, buf);
  480.        }
  481.  
  482.        if( lng_opt & msk)
  483.        {
  484.            pr_off( off_opt, loffset);
  485.            pr_long( lng_opt & msk, num_byt, buf);
  486.        }
  487.  
  488.        } /* end of for */
  489.  
  490.        loffset += num_byt;
  491.  
  492.    } /* end of while */
  493.  
  494.    /*[1]  1-21-85 kpc should print the offset once more so the person
  495.     *[1] knows where the file ended.
  496.     */
  497.    Off_prflg = FALSE;           /*[1]*/
  498.    pr_off( off_opt, loffset);       /*[1]*/
  499.    printf("\n");                   /*[1]*/
  500.  
  501. } /*  end of main */
  502.  
  503.  
  504.  
  505.  
  506. pr_usage()
  507. {
  508.    fprintf(stderr,
  509.     "usage: od [-bcdoxDOX B{odxc} w A{odx}] [file] [[+]offset[.][b]]\n"
  510.    );
  511.    exit( 1);
  512. }
  513.  
  514. bclear( p, n)
  515. char   *p;
  516. int    n;
  517. {
  518.    while( n-- )
  519.        *p++ = '\0';
  520. }
  521.  
  522. bcmp( d, s, n)
  523. char   *d,
  524.        *s;
  525. int    n;
  526. {
  527.    while( n-- )
  528.        if( *d++ != *s++ )
  529.        return( FALSE);
  530.  
  531.    return( TRUE);
  532. }
  533.  
  534. bcpy( d, s, n)
  535. char   *d,
  536.        *s;
  537. int    n;
  538. {
  539.    while( n--)
  540.        *d++ = *s++;
  541. }
  542.  
  543.  
  544. /*
  545.  * pr_byte()
  546.  */
  547. pr_byte( opt, w, p)
  548. int    opt,
  549.        w;      /* width */
  550. char   *p;
  551. {
  552.    char    *fmt;
  553.  
  554.    switch( opt )
  555.    {
  556.        case OCT:
  557.        fmt = "%1s%03o";
  558.        break;
  559.  
  560.        case DEC:
  561.        fmt = "%1s%3d";
  562.        break;
  563.  
  564.        case HEX:
  565.        fmt = "%2s%2x";
  566.        break;
  567.  
  568.        case ASC:
  569.        /* here we use our own loop... */
  570.        for( ; w>0; w--,p++)
  571.            if( *p >= ' ' && *p <= '~' )    /*GROT ascii only!!! */
  572.            printf("%4c", *p);
  573.            else if( *p == '\0') /* null */
  574.            printf("  \\0");
  575.            else if( *p == '\n') /* newline */
  576.            printf("  \\n");
  577.            else if( *p == '\f') /* formfeed */
  578.            printf("  \\f");
  579.            else if( *p == '\b') /* backspace */
  580.            printf("  \\b");
  581.            else if( *p == '\r') /* carriage return */
  582.            printf("  \\r");
  583.            else if( *p == '\t') /* tab */
  584.            printf("  \\t");
  585.            else
  586.            printf(" %03o", *p & 0x00ff);
  587.  
  588.        printf("\n");
  589.        return;
  590.  
  591.        default:
  592.        return;
  593.    }
  594.  
  595.  
  596.    for( ; w>0; w--)
  597.        printf( fmt, " ", *p++ & 0x00ff);
  598.  
  599.    printf("\n");
  600. }
  601.  
  602.  
  603. pr_short( opt, w, p)
  604. int    opt,
  605.        w;      /* width */
  606. short  *p;
  607. {
  608.    char    *fmt;
  609.  
  610.    switch( opt )
  611.    {
  612.        case OCT:
  613.        fmt = "%2s%06o";
  614.        break;
  615.  
  616.        case DEC:
  617.        fmt = "%3s%05d";
  618.        break;
  619.  
  620.        case USGN:
  621.        fmt = "%3s%05u";
  622.        break;
  623.  
  624.        case HEX:
  625.        fmt = "%4s%04x";
  626.        break;
  627.  
  628.        default:
  629.        return;
  630.    }
  631.  
  632.  
  633.    for( w /= 2 ; w>0; w--)
  634.        printf( fmt, " ", *p++);
  635.  
  636.    printf("\n");
  637. }
  638.  
  639.  
  640. /*
  641.  * pr_long()
  642.  * print out longs   either 4 or 6 longs depending on the width.
  643.  */
  644. pr_long( opt, w, p)
  645. int    opt,
  646.        w;     /* width */
  647. long   *p;
  648. {
  649.    char    *fmt;
  650.  
  651.    switch( opt )
  652.    {
  653.        case OCT:
  654.        fmt = "%4s%012lo";
  655.        break;
  656.  
  657.        case DEC:
  658.        fmt = "%6s%010ld";
  659.        break;
  660.  
  661.        case USGN:
  662.        fmt = "%6s%010lu";
  663.        break;
  664.  
  665.        case HEX:
  666.        fmt = "%8s%08lx";
  667.        break;
  668.  
  669.        default:
  670.        return;
  671.    }
  672.  
  673.  
  674.    for( w /= 4; w>0; w--)
  675.        printf( fmt, " ", *p++);
  676.  
  677.    printf("\n");
  678. }
  679.  
  680.  
  681. /*
  682.  * pr_off()
  683.  * print the current offset or enough blanks to cover the space
  684.  */
  685. pr_off( opt, lpos )
  686. int    opt;    /* formating option, OCT DEC HEX */
  687. long   lpos;   /* the current offset */
  688. {
  689.    char    *fmt;
  690.  
  691.    if( Off_prflg)
  692.        printf("%9s", " ");
  693.    else
  694.    {
  695.        switch( opt)
  696.        {
  697.        case OCT:
  698.            fmt = "%08lo ";
  699.            break;
  700.  
  701.        case DEC:
  702.            fmt = "%8ld.";
  703.            break;
  704.  
  705.        case HEX:
  706.            fmt = "%08lx ";
  707.            break;
  708.        }
  709.  
  710.        Off_prflg = TRUE;
  711.        printf( fmt, lpos);
  712.    }
  713. }
  714.